#include "PCREPP.hpp"
#include <string.h>

PCRE::replacef::replacef()
	: substr_set(NULL), format_str(NULL), format_vector(NULL), valid_elem(0), substr_count(0)
{
}

PCRE::replacef::~replacef()
{
	if (format_vector)
		delete [] format_vector;
}

void PCRE::replacef::Attach(const char *replace_str)
{
	int count = 0;
	size_t pos, p_start, len;

	format_str = (char *) replace_str;
	len = strlen(format_str);

	for (;*replace_str;replace_str++)
		if (*replace_str == '\\' || *replace_str == '$')
			count++;

	format_vector = new int [(count << 2) + 2];

	pos = 0;
	p_start = 0;
	valid_elem = 0;
	while (pos < len) {
		pos += strcspn(format_str + pos, "\\$");

#define SET_VECTOR() {if (pos > p_start) {format_vector[valid_elem++] = p_start;format_vector[valid_elem++] = pos;}}

		switch (format_str[pos]) {
			case '\\':
				SET_VECTOR();
				p_start = ++pos;
				pos++;
			break;
			case '$':
				if ((format_str[pos + 1] >= '1' && format_str[pos + 1] <= '9') || format_str[pos + 1] == '&') {
					SET_VECTOR();
					format_vector[valid_elem++] = -1;
					format_vector[valid_elem++] = (format_str[pos + 1] == '&') ? 0 : (int) format_str[pos + 1] - (int) '0';
					pos += 2;
					p_start = pos;
				}
				else pos++;
			break;
		}
	}
	SET_VECTOR();

#undef SET_VECTOR
}

void PCRE::replacef::Detach()
{
	if (format_vector)
		delete [] format_vector;
	format_vector = NULL;
	format_str = NULL;
	valid_elem = 0;
}

size_t PCRE::replacef::ParseLength()
{
	size_t len = 0;
	int i, s;

	for (i = 0;i < valid_elem;i += 2) {
		if (format_vector[i] >= 0)
			len += format_vector[i + 1] - format_vector[i];
		else {
			s = format_vector[i + 1];
			if (s < substr_count && substr_set[s] != NULL) {
				len += strlen(substr_set[s]);
			}
		}
	}

	return len;
}

void PCRE::replacef::Parse(char *result)
{
	int i, s;

	for (i = 0;i < valid_elem;i += 2) {
		if (format_vector[i] >= 0) {
			s = format_vector[i + 1] - format_vector[i];
			strncpy(result, format_str + format_vector[i], s);
			result += s;
		}
		else {
			s = format_vector[i + 1];
			if (s < substr_count && substr_set[s] != NULL) {
				strcpy(result, substr_set[s]);
				result += strlen(substr_set[s]);
			}
		}
	}

	*result = '\0';
}

void PCRE::replacef::SetSubstringList(char **substr_list, int count)
{
	substr_set = substr_list;
	substr_count = count;
}

char *PCRE::str_realloc(char *&oldBuffer, const size_t newSize)
{
	char *newBuffer = new char [newSize];
	strcpy(newBuffer, oldBuffer);
	delete [] oldBuffer;
	oldBuffer = newBuffer;
	return oldBuffer;
}

#if defined _MFC_BULID || defined __AFXWIN_H__
int PCRE::replace(const char *pattern, const char *replacement, CStringA &target, int flags/* = 0*/)
{
	char *str = NULL;
	int err_code;

	err_code = replace(pattern, replacement, (const char *) target, str, 0, flags);

	if (err_code == 0)
		target = str;
	if (str)
		delete [] str;

	return err_code;
}

int PCRE::replace(const wchar_t *pattern, const wchar_t *replacement, CStringW &target, int flags/* = 0*/)
{
	wchar_t *str = NULL;
	int err_code;

	err_code = replace(pattern, replacement, (const wchar_t *) target, str, 0, flags);

	if (err_code == 0)
		target = str;
	if (str)
		delete [] str;

	return err_code;
}
#endif
